import { Container,CanvasSource,Graphics} from "pixi.js";
import { Sprite } from "@/sprites/Sprite.js";
import { config } from "@/managers/ConfigManager.js";
export class Weather extends Container {
    constructor() {
        super();

        this._width = config.width;
        this._height = config.height;
        /**
         * @type {Sprite[]}
         */
        this.visiblesprites = [];
        /**
         * @type {Sprite[]}
         */
        this.hideSprites=[];
        this.hideCap=8;

        this.rainSource=null;
        this.stormSource=null;
        this.snowSource=null;
        this.dimmer=null;
        this.type = 'none';
        this.power = 0;

        this.base={x:0,y:0};
        
        this.createDimmer();

        this.visible=false;

        this.updateSprites={
            'rain':this.updateRainSprites,
            'storm':this.updateStormSprites,
            'snow':this.updateSnowSprites
        };

        this.crtUpdate=null;
        this.attachHandler();
    }

    destroy(opts){
        opts=opts||{children:true};
        if(opts.textureSource){
            opts.textureSource=false;
        }
        opts.children=true;
        this.visiblesprites.length=0;
        this.hideSprites.length=0;
        this.deattachHandler();
        super.destroy(opts);
        this.rainSource?.destroy();
        this.stormSource?.destroy();
        this.snowSource?.destroy();
    }

    attachHandler(){
        $gameScreen.on('screen:weather',this.onWeatherEvents);
        $gameMap.on('map:display',this.onDisplayEvents);
    }

    deattachHandler(){
        $gameScreen.off('screen:weather',this.onWeatherEvents);
        $gameMap.off('map:display',this.onDisplayEvents);
    }

    onWeatherEvents=(type)=>{
        switch(type){
            case 'type':
                this.updateWeatherType();
                break;
            case 'power':
                this.updateWeatherPower();
                break;
        }
    }

    onDisplayEvents=(type)=>{
        if(type=='changed'){
            this.updateBasePosition();
        }
    }

    updateWeatherType(){
        this.type=$gameScreen.weatherType();
        this.crtUpdate=this.updateSprites[this.type];
        this.visible=!!this.crtUpdate;
    }

    updateBasePosition(){
        this.base.x=$gameMap.displayX() * $gameMap.tileWidth();
        this.base.y=$gameMap.displayY() * $gameMap.tileHeight();
    }

    updateWeatherPower(){
        this.power=$gameScreen.weatherPower();
        this.updateSpriteCount();
        this.updateDimmer();
    }

    updateDimmer() {
        this.dimmer.alpha = this.power*6/255;
    }

    updateSpriteCount(){
        let maxLen = Math.floor(this.power * 10);
        let len=this.visiblesprites.length;
        if(len<maxLen){
            let diff=maxLen-len;
            while(diff>0){
                --diff;
                this.visiblesprites.push(this.newSprite());
            }
        }else if(len>maxLen){
            for(let i=maxLen;i<len;++i){
                let sprite=this.visiblesprites[i];
                sprite.visible=false;
                if(this.hideSprites.length>=this.hideCap){
                    this.removeChild(sprite);
                    sprite.destroy({children:true,texture:true});
                }else{
                    this.hideSprites.push(sprite);
                }
            }
            this.visiblesprites.length=len;
        }
    }

    update() {
        if(this.visible){
            this.crtUpdate();
        }
    }

    createDimmer() {
        this.dimmer = new Graphics();
        this.dimmer.rect(0,0,config.width,config.height).fill(0x505050);
        this.addChild(this.dimmer);
        this.updateDimmer();
    }
    
    createRainSource(){
        if(!this.rainSource){
            this.rainSource=new CanvasSource({width:1,height:60});
            let context=this.rainSource.context2D;
            context.fillStyle='#fff';
            context.fillRect(0,0,1,60);
        }
    }

    createStormSource(){
        if(!this.stormSource){
            this.stormSource=new CanvasSource({width:2,height:100});
            let context=this.stormSource.context2D;
            context.fillStyle='#fff';
            context.fillRect(0,0,2,100);
        }
    }
    createSnowSource(){
        if(!this.snowSource){
            this.snowSource=new CanvasSource({width:9,height:9});
            let context=this.snowSource.context2D;
            context.fillStyle='#fff';
            context.arc(4,4,4,0,Math.PI*2,false);
            context.fill();
        }
    }

    newSprite(){
        let sprite=null;
        if(this.hideSprites.length>0){
            sprite=this.hideSprites.pop();
            sprite.visible=true;
        }else{
            sprite=new Sprite();
        }
        sprite.alpha=0;
        sprite.ax=0;
        sprite.ay=0;
        return sprite;
    }

    updateRainSprites=()=> {
        this.createRainSource();
        for(let sprite of this.visiblesprites){
            if(sprite.source!=this.rainSource){
                sprite.source=this.rainSource;
            }
            sprite.rotation = Math.PI / 16;
            sprite.ax -= 6 * Math.sin(sprite.rotation);
            sprite.ay += 6 * Math.cos(sprite.rotation);
            sprite.alpha -= 0.02;
            if (sprite.alpha < 0.16) {
                this.rebornSprite(sprite);
            }
            sprite.x = sprite.ax - this.base.x;
            sprite.y = sprite.ay - this.base.y;
        }
    }

    updateStormSprites=()=> {
        this.createStormSource();
        for(let sprite of this.visiblesprites){
            if(sprite.source!=this.stormSource){
                sprite.source=this.stormSource;
            }
            sprite.rotation = Math.PI / 8;
            sprite.ax -= 8 * Math.sin(sprite.rotation);
            sprite.ay += 8 * Math.cos(sprite.rotation);
            sprite.opacity -= 0.03;
            if (sprite.alpha < 0.16) {
                this.rebornSprite(sprite);
            }
            sprite.x = sprite.ax - this.base.x;
            sprite.y = sprite.ay - this.base.y;
        }
    }

    updateSnowSprites=()=> {
        this.createSnowSource();
        for(let sprite of this.visiblesprites){
            if(sprite.source!=this.snowSource){
                sprite.source=this.snowSource;
            }
            sprite.rotation = Math.PI / 16;
            sprite.ax -= 8 * Math.sin(sprite.rotation);
            sprite.ay += 8 * Math.cos(sprite.rotation);
            sprite.opacity -= 0.01;
            if (sprite.alpha < 0.16) {
                this.rebornSprite(sprite);
            }
            sprite.x = sprite.ax - this.base.x;
            sprite.y = sprite.ay - this.base.y;
        }
    }

    rebornSprite(sprite) {
        sprite.ax = Math.random()*(config.width + 100) - 100 + this.base.x;
        sprite.ay = Math.random()*(config.height + 200) - 200 + this.base.y;
        sprite.alpha = Math.random()*0.26+0.63;//160+0~60
    }
}